import pandas as pd
from ..calendar import *
from .utils import wind_engine
from empyrical import (
    alpha,
    beta,
    alpha_beta_aligned,
    annual_volatility,
    cum_returns,
    annual_return,
    downside_risk,
    max_drawdown,
    sharpe_ratio,
    sortino_ratio,
    calmar_ratio,
    omega_ratio,
    tail_ratio,
    excess_sharpe
)

def get_fund_nav(code, begindate='20030101',enddate='20990101'):
    if isinstance(code,list):
        code.append('myholds')
        code = tuple(code)
        sql="""
        select * from ChinaMutualFundNAV where F_INFO_WINDCODE in {0} and PRICE_DATE>='{1}' and PRICE_DATE<='{2}'
        order by F_INFO_WINDCODE,PRICE_DATE 
        """.format(code,begindate,enddate)
        print(sql)
        fundnav=pd.read_sql(sql,wind_engine)
        return fundnav
    else:
        raise TypeError('code must be a list!')

def get_fund_info(code):
    if isinstance(code,list):
        code.append('myholds')
        code = tuple(code)
        sql="""
        select * from ChinaMutualFundDescription where F_INFO_WINDCODE in {0} 
        order by F_INFO_WINDCODE,F_INFO_ISSUEDATE 
        """.format(code)
        print(sql)
        fundinfo=pd.read_sql(sql,wind_engine)
        return fundinfo
    else:
        raise TypeError('code must be a list!')


def print_fund_info(fundinfo):
    print("*******FundBasic**********")
    print('基金代码:{0}'.format(fundinfo['F_INFO_WINDCODE'].values[0]))
    print('基金名称:{0}'.format(fundinfo['F_INFO_FULLNAME'].values[0]))
    print('基金简称:{0}'.format(fundinfo['F_INFO_NAME'].values[0]))
    print('基金管理人:{0}'.format(fundinfo['F_INFO_CORP_FUNDMANAGEMENTCOMP'].values[0]))
    print('基金托管人:{0}'.format(fundinfo['F_INFO_CUSTODIANBANK'].values[0]))
    print('基金投资类型:{0}'.format(fundinfo['F_INFO_FIRSTINVESTTYPE'].values[0]))
    print('基金成立日期:{0}'.format(fundinfo['F_INFO_SETUPDATE'].values[0]))
    print('基金到期日期:{0}'.format(fundinfo['F_INFO_MATURITYDATE'].values[0]))
    print('基金管理费:{0}'.format(fundinfo['F_INFO_MANAGEMENTFEERATIO'].values[0]))
    print('基金托管费:{0}'.format(fundinfo['F_INFO_CUSTODIANFEERATIO'].values[0]))
    print('基金投资风格:{0}'.format(fundinfo['F_INFO_FIRSTINVESTSTYLE'].values[0]))
    print('基金投资理念:{0}'.format(fundinfo['F_INFO_INVESTCONCEPTION'].values[0]))
    print('基金投资目标:{0}'.format(fundinfo['F_INFO_INVESTOBJECT'].values[0]))
    print('基金投资策略:{0}'.format(fundinfo['INVESTSTRATEGY'].values[0]))
    print("*******FundBasic End**********")


def get_fund_manger(code):
    if isinstance(code,list):
        code.append('myholds')
        code = tuple(code)
        sql="""
        select * from ChinaMutualFundManager where F_INFO_WINDCODE in {0} 
        order by F_INFO_WINDCODE,ANN_DATE 
        """.format(code)
        print(sql)
        fundmanger=pd.read_sql(sql,wind_engine)
        return fundmanger
    else:
        raise TypeError('code must be a list!')


def get_fund_nav_analysis(fundnav, bdate=None, edate=None):
    fund_nav = fundnav[['F_INFO_WINDCODE','PRICE_DATE','F_NAV_ADJUSTED']]
    if bdate:
        fund_nav = fund_nav[fund_nav.PRICE_DATE>=bdate]
    if edate:
        fund_nav = fund_nav[fund_nav.PRICE_DATE<=edate]
    fund_nav['fundret'] = fund_nav.F_NAV_ADJUSTED.pct_change()
    fund_nav.set_index('PRICE_DATE',inplace = True)
    returns=fund_nav['fundret']

    # 计算年化收益
    annualreturn = annual_return(returns)
    # 计算最大回撤
    maxdrawdown = max_drawdown(returns)
    # 年化Volatility (策略波动率):用来测量策略的风险性，波动越大代表策略风险越高。
    annualvolatility = annual_volatility(returns['20190101':], period='daily')
    # Calmar比率:Calmar比率描述的是收益和最大回撤之间的关系。计算方式为年化收益率与历史最大回撤之间的比率。Calmar比率数值越大，基金的业绩表现越好。反之，基金的业绩表现越差。
    calmarratio = calmar_ratio(returns)
    # Omega比率
    # 介绍： Omega函数是用来分析收益分布的一种方法，它是一种天然的业绩指标。基于Omega的分析是在下跌，下偏矩和损益文献的精神上进行的。Omega函数捕捉到在收益分布上的所有高阶矩信息并且影响收益水平的敏感性。
    # 公式意义：Omega越高越好，它是对偏度和峰值的一个调整。
    omegaratio = omega_ratio(returns=returns, risk_free=0)
    # Sharpe比率:核心思想：理性的投资者将选择并持有有效的投资组合.公式意义：夏普指数代表投资人每多承担一分风险，可以拿到几分收益；若为正值，代表基金收益率高过波动风险；若为负值，代表基金操作风险大过于收益率。每个投资组合都可以计算Sharpe ratio，即投资回报与多冒风险的比例，这个比例越高，投资组合越佳。
    sharperatio = sharpe_ratio(returns=returns)
    # sortino比率
    # 介绍： Sortino ratio是一个能够评价投资资产、组合或者策略收益的指标。它是夏普比率的修正，它只对收益低于某个值的波动性进行衡量，这个值可能是持有者规定的目标收益或者是要求收益，而夏普比率是同时对上涨的和下降的波动进行衡量。尽管这两个比率都衡量的是一个调整后的投资风险，但它们的意义却不同，这导致投资的收益的结果不同。
    # 核心思想： 公式及其解释:R是资产或组合的预期收益，T是投资策略的目标或要求的收益，起源于最小可接受收益。DR是目标方差的平方根。也就是二阶低偏矩。 Sharpe and Omega-Sharpe ratio的一个自然扩展就是由Sortino在1991年提出的，他使用的是downside risk作为分母，downside risk就是二阶下偏矩。 总风险用下降风险所代替，因为投资组合经理不会被上涨的变化而惩罚，但会被低于最小目标收益的变化而惩罚。 用下降标准差而不是总标准差，以区别不利和有利的波动。
    sortinoratio = sortino_ratio(returns=returns)
    # 下降风险
    downsiderisk = downside_risk(returns=returns)
    # Tail Ratio
    tailratio = tail_ratio(returns=returns)

    fundstat = pd.DataFrame(
        [ maxdrawdown, annualreturn, calmarratio, omegaratio, sharperatio, sortinoratio, downsiderisk,
         tailratio], index=[ 'maxdrawdown', 'annualreturn', 'calmarratio', 'omegaratio', 'sharperatio',
                            'sortinoratio', 'downsiderisk', 'tailratio']).T
    return fundstat


def update_data(path, func, step=True, b_dt=None, **kwargs):
    """
    path：文件保存地点
    func: 数据获取函数
    """
    try:
        df = pd.read_msgpack(path)
        last_day = df['trade_dt'].max()
        if step:
            begin_dt = step_trade_date(last_day, 1)
        else:
            begin_dt = last_day
        if begin_dt > adjust_to_trade_date(dt.date.today()):
            return
    except ValueError:
        df = pd.DataFrame()
        begin_dt = None
        if b_dt:
            begin_dt = b_dt

    #########################
    df_append = func(begin_dt=begin_dt, **kwargs)
    df = pd.concat([df, df_append], axis=0, ignore_index=True, sort=True)
    if not df.empty:
        df.drop_duplicates(inplace=True)
        df.to_msgpack(path)
